﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace DataService.Core.Extensions
{
    /// <summary>
    /// 动态转换实体（字段类型、属性名保持一致 例TIn.v1 Tout.v2；v1 和v2 字段类型、字段名 需要一致）
    /// 调用测试 T2 t2 = ExpressionMapper<T1, T2>.Trans(t1);
    /// </summary>
    public static class MapperExtensions<TIn, TOut> where TOut : new()
    {

        private static Func<TIn, TOut> _FUNC = null;
        static MapperExtensions()
        {
            ParameterExpression parameterExpression = Expression.Parameter(typeof(TIn), "p");
            List<MemberBinding> memberBindingList = new List<MemberBinding>();
            PropertyInfo[] inPropertyInfos = typeof(TIn).GetProperties();
            foreach (var item in typeof(TOut).GetProperties())
            {
                var tempPropertyInfo = inPropertyInfos.FirstOrDefault(x => x.Name == item.Name);
                if (tempPropertyInfo != null)
                {
                    if (tempPropertyInfo.PropertyType.Name != item.PropertyType.Name)
                    {
                        throw new Exception($"{item.Name},属性类型不一致");
                    }
                    MemberExpression property = Expression.Property(parameterExpression, tempPropertyInfo);
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }

            }
            var inFields = typeof(TIn).GetFields();
            foreach (var item in typeof(TOut).GetFields())
            {
                var tempInField = inFields.FirstOrDefault(x => x.Name == item.Name);
                if (tempInField != null)
                {
                    if (tempInField.FieldType.Name != item.FieldType.Name)
                    {
                        throw new Exception($"{item.Name},字段类型不一致");
                    }
                    MemberExpression property = Expression.Field(parameterExpression, tempInField);
                    MemberBinding memberBinding = Expression.Bind(item, property);
                    memberBindingList.Add(memberBinding);
                }
            }
            MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(typeof(TOut)), memberBindingList.ToArray());
            Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(memberInitExpression, new ParameterExpression[]
            {
                    parameterExpression
            });
            _FUNC = lambda.Compile();//拼装是一次性的
        }

        public static TOut Trans(TIn t)
        {
            return _FUNC(t);
        }
        /// <summary>
        /// 实体转换
        /// </summary>
        public static TOut MapperExtensionsTo(TIn t)
        {
            TOut tout = new TOut();
            var fromPropertys = t.GetType().GetProperties();
            var toPropertys = tout.GetType().GetProperties();
            foreach (var p in fromPropertys)
            {
                var eProp = toPropertys.FirstOrDefault(w => w.Name.ToLower() == p.Name.ToLower());
                if (eProp != null)
                {
                    var value = p.GetValue(t);
                    eProp.SetValue(tout, ReturnFormalValue(eProp, value));
                }
            }
            return tout;
        }
        private static object ReturnFormalValue(PropertyInfo pi, object value)
        {
            object formalValue = null;
            if (value == null || string.IsNullOrEmpty(value.ToString()))
            {
                return null;
            }
            if (pi.PropertyType == typeof(string))
            {
                formalValue = value.ToString();
            }
            else if (pi.PropertyType == typeof(int) || pi.PropertyType == typeof(int?))
            {
                if (string.IsNullOrEmpty(value.ToString()))
                {
                    formalValue = 0;
                }
                else
                {
                    int tempValue = 0;
                    int.TryParse(value.ToString(), out tempValue);
                    formalValue = tempValue;

                }
            }
            else if (pi.PropertyType == typeof(bool?) || pi.PropertyType == typeof(bool))
            {

                //int.TryParse(value.ToString(), out int tempValue);
                //formalValue = tempValue > 0;
                formalValue = value;
            }
            else if (pi.PropertyType == typeof(DateTime?) || pi.PropertyType == typeof(DateTime))
            {
                DateTime.TryParse(value.ToString(), out DateTime time);
                formalValue = time;
            }
            else if (pi.PropertyType == typeof(float))
            {
                float tempValue = 0;
                float.TryParse(value.ToString(), out tempValue);
                formalValue = tempValue;
            }
            else if (pi.PropertyType == typeof(double))
            {
                double tempValue = 0;
                double.TryParse(value.ToString(), out tempValue);
                formalValue = tempValue;
            }
            else if (pi.PropertyType == typeof(decimal) || pi.PropertyType == typeof(decimal?))
            {
                decimal tempValue = 0;
                decimal.TryParse(value.ToString(), out tempValue);
                formalValue = tempValue;
            }
            else if (pi.PropertyType == typeof(Guid) || pi.PropertyType == typeof(Guid?))
            {
                formalValue = new Guid(value.ToString());
            }
            else
            {
                formalValue = value;
            }
            return formalValue;
        }
    }
}
